<?php
/**
 * @author spenceryg
 * @date 2023/3/15
 * @time 6:10 下午
 * @focus love & life
 */


namespace app\common\lib;


use app\common\lib\verify\AliSmsVerify;
use app\common\lib\verify\VerifyFactory;
use app\common\model\ApikeyLibrary;
use app\common\model\GptToken;
use GuzzleHttp\Client;
use Orhanerday\OpenAi\OpenAi;
use think\facade\Log;

class ChatGptBak
{

    public static function chatSocket($msg, $connection, $returnLine = false)
    {
        $client = new Client([
            // Base URI is used with relative requests
//            'base_uri' => 'https://api.openai.com/v1/chat/completions',
            'base_uri' => config('transfer.transit_address'),

            // You can set any number of default request options.
            'timeout' => 80,
        ]);

//        $token = GptToken::where('id' ,'=', 1)->value('token');
        $tokenModel = GptToken::order('update_time', 'asc')->where('id', '>', 0)->find();
        $token = $tokenModel['token'];
        $tokenModel->force()->save();

        try{
            $res = $client->request('post', '', [
                'verify' => false,
                'headers' => [
                    'Authorization' => "Bearer {$token}",
                ],
                'stream' => true,
                'json' => [
                    'model' => 'gpt-3.5-turbo',
                    'messages' => is_array($msg) ? $msg : [
                        [
                            "role" => "user",
                            "content" => $msg
                        ],
                    ],
                    'stream' => true
                ],
            ]);
        }catch (\Exception $e){
            $msg = $e->getResponse()->getReasonPhrase();
            $apiKey = ApikeyLibrary::where('state', 0)->order('id', 'asc')->find();
            if($apiKey){
                $gptToken = GptToken::where('token', $token)->find();
                $gptToken->token = $apiKey->name;
                $gptToken->save();
//                GptToken::where('token', $token)->save(['token'=>$apiKey->name]);
                $apiKey->state = 1;
                $apiKey->usage_time = date('Y-m-d H:i:s', time());
                $apiKey->save();

                $oldApiKey = ApikeyLibrary::where('name', $token)->find();
                $oldApiKey->end_time = date('Y-m-d H:i:s', time());
                if($msg == 'Unauthorized'){
                    $oldApiKey->state = 3;
                }else{
                    $oldApiKey->state = 2;
                }
                $oldApiKey->end_reason = $msg;
                $oldApiKey->save();
            }else{
                $factory = new VerifyFactory(new AliSmsVerify());
                $factory->setTo('15821183928')->setCode('88888888')->send();
            }

        }



        $body = $res->getBody();
        $arr = [];
        $last_data = '######';
        $titles = [];
        $one_line = '';
        $response_content = '';


        while (!$body->eof()) {
            $arr[] = $body->read(1200);
            $length = sizeof($arr);

            $words = explode("\n\n", $arr[$length - 1]);
//                Log::channel('gpt')->info($words);
            foreach ($words as $word_index => $word) {
                $full_data = json_decode(str_replace('data: ', '', $word), true);
                $finish_reason = null;
                $this_str = '####';
                if ($full_data) {
                    $finish_reason = $full_data['choices'][0]['finish_reason'];
                    if (!$finish_reason) {
                        $word_arr[] = $full_data;
                        if(isset($full_data['choices'][0]['delta']['content']) ){
                            $this_str =  $full_data['choices'][0]['delta']['content'];
                        }
                    }
                } else {
                    if ($word_index != 0) {
                        $last_data = $word;
                    } else {
                        $full_data = json_decode(str_replace('data: ','',$last_data . $word ), true);
                        if($full_data){
                            $finish_reason = $full_data['choices'][0]['finish_reason'];
                            if (!$finish_reason) {
                                $word_arr[] = $full_data;
                                $this_str = $full_data['choices'][0]['delta']['content'];
                            }
                            $last_data = '######';
                        }

                    }
                }



                if ($returnLine) {
                    if ($this_str !== '####') {
                        $one_line .= $this_str;
                        if (strpos($this_str, "\n") !== false) {
                            if (trim($one_line) !== '') {
                                $titles[] = trim($one_line);
                                $connection->send(
                                   json_encode([
                                       'type' => 'chat',
                                       'content' =>  explode(' ', $titles[sizeOf($titles) - 1], 2)[1]
                                   ])
                                );
                            }
                            $one_line = '';
                        }
                    }
                } else {
                    if ($this_str !== '####' ) {
                        $response_content .= $this_str;
                        $connection->send(json_encode([
                            'type' => 'chat',
                            'content' => $this_str
                        ]));
                    }
                }

                if ($finish_reason) {
                    return $response_content;
                }

            }
        }
    }

    public static function chat($msg, $stream = false, $event_name = '', $returnLine = true, $event_handle = false,$is_json = true)
    {
        $client = new Client([
            // Base URI is used with relative requests
            //'base_uri' => 'http://test.ai-dog.net/index/chat',
            'base_uri' => config('transfer.transit_address'),

            // You can set any number of default request options.
            'timeout' => 80,
        ]);

//        $token = GptToken::where('id' ,'=', 1)->value('token');
        $tokenModel = GptToken::order('update_time', 'asc')->where('id', '>', 0)->find();
        $token = $tokenModel['token'];
        $tokenModel->force()->save();

        try{
            $res = $client->request('post', '', [
                'verify' => false,
                'headers' => [
                    'Authorization' => "Bearer {$token}",
                ],
                'stream' => $stream,
                'json' => [
                    'model' => 'gpt-3.5-turbo',
                    'messages' => is_array($msg) ? $msg : [
                        [
                            "role" => "user",
                            "content" => $msg
                        ],
                    ],
                    'stream' => $stream
                ],
            ]);
        }catch (\Exception $e){
            $msg = $e->getResponse()->getReasonPhrase();
            $apiKey = ApikeyLibrary::where('state', 0)->order('id', 'asc')->find();
            if($apiKey){

                $gptToken = GptToken::where('token', $token)->find();
                $gptToken->token = $apiKey->name;
                $gptToken->save();
//                GptToken::where('token', $token)->save(['token'=>$apiKey->name]);

                $apiKey->state = 1;
                $apiKey->usage_time = date('Y-m-d H:i:s', time());
                $apiKey->save();

                $oldApiKey = ApikeyLibrary::where('name', $token)->find();
                $oldApiKey->end_time = date('Y-m-d H:i:s', time());
                if($msg == 'Unauthorized'){
                    $oldApiKey->state = 3;
                }else{
                    $oldApiKey->state = 2;
                }
                $oldApiKey->end_reason = $msg;
                $oldApiKey->save();
            }else{
                //$factory = new VerifyFactory(new AliSmsVerify());
                //$factory->setTo('15821183928')->setCode('88888888')->send();
            }
        }



        if ($stream) {
            $response_content = '';
            header('X-Accel-Buffering: no');
            header('Content-Type: text/event-stream');
            header('Cache-Control: no-cache');

            //跨域
            header('Access-Control-Allow-Origin: *');
            header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
            header('Access-Control-Allow-Headers: Content-Type');

            set_time_limit(0); //防止超时
            ob_end_clean();
            ob_implicit_flush(1);

            $body = $res->getBody();
            $arr = [];
            $last_data = '######';
            $titles = [];
            $one_line = '';

            while (!$body->eof()) {
                $arr[] = $body->read(1200);
                $length = sizeof($arr);
                $words = explode("\n\n", $arr[$length - 1]);
                Log::channel('gpt')->info($words);
                foreach ($words as $word_index => $word) {
                    $full_data = json_decode(str_replace('data: ', '', $word), true);
                    $finish_reason = null;
                    $this_str = '####';
                    if ($full_data) {
                        $finish_reason = $full_data['choices'][0]['finish_reason'];
                        if (!$finish_reason) {
                            $word_arr[] = $full_data;
                            if(isset($full_data['choices'][0]['delta']['content']) ){
                                $this_str =  $full_data['choices'][0]['delta']['content'];
                            }
                        }
                    } else {
                        if ($word_index != 0) {
                            $last_data = $word;
                        } else {
                            $full_data = json_decode(str_replace('data: ', '', $last_data . $word), true);
                            if($full_data){
                                $finish_reason = $full_data['choices'][0]['finish_reason'];
                                if (!$finish_reason) {
                                    $word_arr[] = $full_data;
                                    $this_str = $full_data['choices'][0]['delta']['content'];
                                }
                                $last_data = '######';
                            }

                        }
                    }

                    if ($returnLine) {
                        if ($this_str !== '####') {
                            $one_line .= $this_str;
                            if (strpos($this_str, "\n") !== false) {
                                if (trim($one_line) !== '') {
                                    $titles[] = trim($one_line);
                                    if ($event_handle) {
                                         self::$event_handle($event_name, $titles[sizeOf($titles) - 1]);
                                    } else {
                                        $c = "event:{$event_name}" . PHP_EOL; //定义事件
                                        $c .= "data:" . $titles[sizeOf($titles) - 1] . PHP_EOL; //推送内容
                                        echo $c . PHP_EOL;

                                    }

                                }
                                $one_line = '';
                            }
                        } else {
                            if ($finish_reason) {
                                $titles[] = trim($one_line);
                                if ($event_handle) {
                                     self::$event_handle($event_name, $titles[sizeOf($titles) - 1]);
                                } else {
                                    $c = "event:{$event_name}" . PHP_EOL; //定义事件
                                    $c .= "data:" . $titles[sizeOf($titles) - 1] . PHP_EOL; //推送内容
                                    echo $c . PHP_EOL;
                                }
                                $one_line = '';
                            }
                        }
                    } else {
                        if ($this_str !== '####' ) {
                            if ($event_handle) {
                                 self::$event_handle($event_name, $titles[sizeOf($titles) - 1]);
                            } else {
                                $c = "event:{$event_name}" . PHP_EOL; //定义事件
                                if($is_json){
                                    $this_str_json = [
                                        'title' => $this_str,
                                    ];
//                                $c .= "data:" . $titles[sizeOf($titles) - 1] . PHP_EOL; //推送内容
                                    $c .= "data:" .json_encode($this_str_json). PHP_EOL; //推送内容
                                }else{
                                    $c .= "data:" . $this_str . PHP_EOL;
                                }

                                echo $c . PHP_EOL;
                                $response_content .= $this_str;
                            }
                        }
                    }

                }
            }
            $c = "event:{$event_name}" . PHP_EOL; //定义事件
            $c .= "data:end" . PHP_EOL; //推送内容
            echo $c . PHP_EOL;
            return $response_content;

        } else {
            $res = $res->getBody()->getContents();
            $res = json_decode($res, true);
            return $res['choices'][0]['message']['content'];
        }

    }

    public static function getTitles($query): array
    {
        $res = self::chat($query);
        $arr = explode("\n", trim($res));
        $res = [];
        foreach ($arr as $item) {
            $res[] = explode(' ', $item, 2)[1];
        }
        return $res;
    }

    public static function sendEvent($event_name, $key)
    {
        Log::channel('title')->info($key);
        $res = '';
        $arr = explode(' ', trim($key), 2);
        if(sizeof($arr) == 2) {
            $key = $arr[1];
        }else{
            $key = $arr[0];
        }
        $data = [
            'title' => $key,
            'is_used' => 0
        ];
        $res = $res . "event:{$event_name}" . PHP_EOL;
        $res = $res . "data:" . json_encode($data) . PHP_EOL;
        echo $res . PHP_EOL;
    }


    public static function sendEventIsUsed($event_name, $key)
    {
        $res = '';
        $key = explode(' ', $key, 2)[1];
        $data = [
            'title' => $key,
            'is_used' => 0
        ];
        $res = $res . "event:{$event_name}" . PHP_EOL;
        $res = $res . "data:" . json_encode($data) . PHP_EOL;
        echo $res . PHP_EOL;
    }
}
